package com.winit.openapi.gt.controller;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.winit.common.query.Page;
import com.winit.common.query.SearchOperator;
import com.winit.common.query.Searchable;
import com.winit.common.query.Sort;
import com.winit.common.query.Sort.Direction;
import com.winit.common.query.filter.SearchFilterHelper;
import com.winit.common.spi.context.CommandContext;
import com.winit.erp.spi.bpartner.vo.Bpartner;
import com.winit.oms.spi.common.vo.SalesCalculateFeeResult;
import com.winit.oms.spi.gt.CustomerPackageService;
import com.winit.oms.spi.gt.GlobalTransferOpFeeService;
import com.winit.oms.spi.gt.GlobalTransferOrderValidateService;
import com.winit.oms.spi.gt.GlobalTransferService;
import com.winit.oms.spi.gt.command.BatchImportPackageCommand;
import com.winit.oms.spi.gt.command.DisableGlobalTransferCommand;
import com.winit.oms.spi.gt.command.EditGlobalTransferCommand;
import com.winit.oms.spi.gt.command.GetByGlobalTransferOrderByNoCommand;
import com.winit.oms.spi.gt.command.GetCustomerPackageLineByPackageIdCommand;
import com.winit.oms.spi.gt.command.GetGlobalTransferCommand;
import com.winit.oms.spi.gt.command.PageGlobalTransferCommand;
import com.winit.oms.spi.gt.command.SaveGlobalTransferCommand;
import com.winit.oms.spi.gt.command.SubmitGlobalTransferCommand;
import com.winit.oms.spi.gt.vo.CustomerPackage;
import com.winit.oms.spi.gt.vo.CustomerPackageLine;
import com.winit.oms.spi.gt.vo.CustomerPackageVO;
import com.winit.oms.spi.gt.vo.GTOrderCustomerAddress;
import com.winit.oms.spi.gt.vo.GlobalTransferOrder;
import com.winit.oms.spi.inbound.InboundOrderService;
import com.winit.oms.spi.inbound.command.VoidInboundOrderCommand;
import com.winit.oms.spi.inbound.vo.InboundEnumConstant;
import com.winit.oms.spi.inbound.vo.InboundVoidOrderRecordVo;
import com.winit.openapi.constants.ApiConstant;
import com.winit.openapi.constants.ErrorCode;
import com.winit.openapi.controller.BaseController;
import com.winit.openapi.exception.ApiException;
import com.winit.openapi.gt.controller.builder.GlobalTransferOrderBuilder;
import com.winit.openapi.model.RequestMsg;
import com.winit.openapi.model.ResponseMsg;
import com.winit.openapi.util.DateUtil;
import com.winit.openapi.util.ValidateUtil;
import com.winit.openapi.wh.utils.PrecisionValidateUtils;
import com.winit.pms.spi.v2.common.PmsConstants;
import com.winit.pms.spi.v2.common.PmsEnumType;
import com.winit.pms.spi.v2.instance.pscInstance.ProductLogisticsDistService;
import com.winit.pms.spi.v2.instance.pscInstance.command.QueryDestCountryCommand;
import com.winit.pms.spi.v2.instance.pscInstance.command.QueryDestWarehouseListCommand;
import com.winit.pms.spi.v2.instance.pscInstance.command.QueryReceiveWarehouseListCommand;
import com.winit.pms.spi.winit.LogisticsdistService;
import com.winit.pms.spi.winit.WinitProductService;
import com.winit.pms.spi.winit.WinitSlaService;
import com.winit.pms.spi.winit.command.LogisticsQueryCommand;
import com.winit.pms.spi.winit.command.QueryWarehouseLogisticsDistCommand;
import com.winit.pms.spi.winit.command.WinitProductQueryCommand;
import com.winit.pms.spi.winit.command.WinitSlaQueryCommand;
import com.winit.pms.spi.winit.vo.LogisticsDist;
import com.winit.pms.spi.winit.vo.SalesCalculatorFee;
import com.winit.pms.spi.winit.vo.WinitProduct;
import com.winit.pms.spi.winit.vo.WinitSla;
import com.winit.ups.spi.systemrule.CountryService;
import com.winit.ups.spi.systemrule.command.CountryCodeCommand;
import com.winit.ups.spi.systemrule.vo.Country;

@Controller
@RequestMapping(value = "/globalTransfer")
public class GlobalTransferController extends BaseController {

    private Logger                             logger = LoggerFactory.getLogger(GlobalTransferController.class);

    @Resource
    private GlobalTransferService              globalTransferService;
    @Resource
    private CustomerPackageService             customerPackageService;
    @Resource
    private GlobalTransferOpFeeService         globalTransferOpFeeService;
    @Resource
    private LogisticsdistService               logisticsdistService;
    @Resource
    private ProductLogisticsDistService        productLogisticsDistService;
    @Resource
    private CountryService                     countryService;
    @Resource
    private InboundOrderService                inboundOrderService;
    @Resource
    private GlobalTransferOrderValidateService globalTransferOrderValidateService;
    @Resource
    private WinitProductService                winitProductService;
    @Resource
    private WinitSlaService                    winitSlaService;

    /**
     * 分页查询国际送仓单
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     * @author LH
     * @throws ParseException
     * @date 2015-6-24
     */
    @RequestMapping(value = "/pageQuery")
    public String pageQuery(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg)
                                                                                                           throws ParseException {
        Object obj = requestMsg.getData();
        PageGlobalTransferCommand command = null;
        CommandContext ctx = CommandContext.getContext();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            validpageParams(json);
            command = buildPageGlobalTransferCommand(json);
            Searchable searchable = buildSearchPageParams(json);
            // 当前用户
            searchable.and(SearchFilterHelper.newCondition("USER_ID", SearchOperator.eq, ctx.getUserId()));

            // 查询条件
            if (StringUtils.isNotEmpty(command.getGlobalTransferNo())) {
                searchable.and(SearchFilterHelper.newCondition("GLOBAL_TRANSFER_NO",
                    SearchOperator.like,
                    "%" + command.getGlobalTransferNo() + "%"));
            }
            if (StringUtils.isNotEmpty(command.getSellerOrderNo())) {
                searchable.and(SearchFilterHelper.newCondition("SELLER_ORDER_NO",
                    SearchOperator.like,
                    "%" + command.getSellerOrderNo() + "%"));
            }
            if (StringUtils.isNotEmpty(command.getWarehouseCode())) {
                searchable.and(SearchFilterHelper.newCondition("WAREHOUSE_CODE",
                    SearchOperator.eq,
                    command.getWarehouseCode()));
            }
            if (StringUtils.isNotEmpty(command.getTransportModeCode())) {
                searchable.and(SearchFilterHelper.newCondition("TRANSPORT_MODE_CODE",
                    SearchOperator.eq,
                    command.getTransportModeCode()));
            }
            if (StringUtils.isNotEmpty(command.getStatus())) {
                if (InboundEnumConstant.OrderStatus.VO.getStatus().equals(command.getStatus())) {
                    String orderStatus = "('" + InboundEnumConstant.OrderStatus.VO.getStatus() + "','"
                                         + InboundEnumConstant.OrderStatus.STOP.getStatus() + "')";
                    searchable.and(SearchFilterHelper.newCondition("STATUS", SearchOperator.in, orderStatus));
                } else {
                    searchable.and(SearchFilterHelper.newCondition("STATUS", SearchOperator.eq, command.getStatus()));
                }
            }
            if (StringUtils.isNotEmpty(command.getProductCode())) {
                searchable.and(SearchFilterHelper.newCondition("WINIT_PRODUCT_CODE",
                    SearchOperator.eq,
                    command.getProductCode()));
            }
            if (StringUtils.isNotEmpty(command.getPscCode())) {
                searchable.and(SearchFilterHelper.newCondition("PSC_CODE", SearchOperator.eq, command.getPscCode()));
            }

            // 下单时间
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            if (null != command.getStartDate()) {
                searchable.addSearchFilter(SearchFilterHelper.newCondition("CREATED",
                    SearchOperator.gte,
                    sdf.format(command.getStartDate()) + " 00:00:00"));

            }
            if (null != command.getEndDate()) {
                searchable.addSearchFilter(SearchFilterHelper.newCondition("CREATED",
                    SearchOperator.lte,
                    sdf.format(command.getEndDate()) + " 23:59:59"));
            }

            command.setSearchable(searchable);
            command.setCtx(ctx);
            Page<GlobalTransferOrder> page = globalTransferService.pageQuery(command);
            if (page != null) {
                Map<String, Object> pageMap = new HashMap<String, Object>();
                pageMap.put("pageNo", page.getPageable().getPageNumber());
                pageMap.put("pageSize", page.getPageable().getPageSize());
                pageMap.put("totalCount", page.getTotalElements());

                Map<String, Object> data = new HashMap<String, Object>();
                data.put("list", page.getContent());
                data.put("pageParams", pageMap);
                responseMsg.setData(data);
            }

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }

    /**
     * 首公里提货服务
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/getPickService")
    public String getPickService(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        // 首公里提货服务（本期版本在代码中定义枚举类型）
        Map<String, String> map = globalTransferService.getPickService();
        responseMsg.setData(map);
        return SUCCESS;
    }

    /**
     * 第三步保存国际送仓单
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/thirdStepSave")
    public String thirdStepSave(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        SaveGlobalTransferCommand command = null;
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            // 校验单据信息是否必填、长度、类型
            validateGlobalTransfer(json);
            // 组装command
            command = (SaveGlobalTransferCommand) buildOrderValidateCommand(json);
            command.setCtx(CommandContext.getContext());
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 第三步保存单据信息
        Integer id = globalTransferService.thirdStepSave(command);
        responseMsg.setData(id);

        return SUCCESS;
    }

    /**
     * 批量导入箱单信息
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/saveSecondStep")
    public String saveSecondStep(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        BatchImportPackageCommand command = new BatchImportPackageCommand();
        List<CustomerPackageVO> voList = new ArrayList<CustomerPackageVO>();
        String winitProductType = null;
        String templateType = null;
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "id");
            ValidateUtil.validMaxLength(json, "id", 20, true);
            command.setId(json.getInteger("id"));

            winitProductType = json.getString("winitProductType");
            command.setWinitProductType(winitProductType);

            templateType = json.getString("templateType");
            command.setTemplateType(templateType);
            if ("FBA".equals(templateType)) {
                if (StringUtils.isEmpty(json.getString("templateAddressCode"))) {
                    ValidateUtil.validNotNull(json, "Ship To");
                }
                command.setTemplateAddressCode(json.getString("templateAddressCode"));
            }

            JSONArray array = json.getJSONArray("packageList");
            for (Object object : array) {
                JSONObject pacakge = (JSONObject) object;
                // 校验单据信息是否必填、长度、类型
                this.validatePackage(pacakge, winitProductType);
                CustomerPackageVO vo = new CustomerPackageVO();
                vo.setCustomerPackageBarcode(pacakge.getString("customerPackageBarcode"));
                vo.setDeclaredCode(pacakge.getString("declaredCode"));
                vo.setSpecification(pacakge.getString("specification"));
                vo.setQuantity(pacakge.getInteger("quantity"));

                vo.setImportWeight(pacakge.getBigDecimal("importWeight").setScale(6, BigDecimal.ROUND_HALF_UP));
                vo.setImportLength(pacakge.getBigDecimal("importLength").setScale(2, BigDecimal.ROUND_HALF_UP));
                vo.setImportWidth(pacakge.getBigDecimal("importWidth").setScale(2, BigDecimal.ROUND_HALF_UP));
                vo.setImportHeight(pacakge.getBigDecimal("importHeight").setScale(2, BigDecimal.ROUND_HALF_UP));
                // 尺寸排序最小为高，最大为长
                BigDecimal[] sort = new BigDecimal[] { vo.getImportLength(), vo.getImportWidth(), vo.getImportHeight() };
                Arrays.sort(sort);
                vo.setImportLength(sort[2]);
                vo.setImportWidth(sort[1]);
                vo.setImportHeight(sort[0]);
                // 计算 体积
                BigDecimal importVolume = vo.getImportLength()
                    .multiply(vo.getImportWidth())
                    .multiply(vo.getImportHeight())
                    .divide(BigDecimal.valueOf(1000000), 9, BigDecimal.ROUND_HALF_UP);

                vo.setImportVolume(importVolume);

                voList.add(vo);
            }
            // 组装command
            command.setVoList(voList);
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 批量导入箱单信息
        responseMsg.setData(globalTransferService.saveSecondStep(command));

        return SUCCESS;
    }

    /**
     * 第四步保存国际送仓单（计算预估费用）
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/chargesEstimate")
    public String chargesEstimate(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "id");
            ValidateUtil.validMaxLength(json, "id", 20, true);
            GetGlobalTransferCommand idCommand = new GetGlobalTransferCommand();
            idCommand.setId(json.getInteger("id"));
            idCommand.setCtx(CommandContext.getContext());

            // 刷新进口申报价值
            globalTransferService.refreshMerchandisesImportDeclareValue(idCommand);

            // 计算预估费用
            SalesCalculateFeeResult result = globalTransferOpFeeService.estimateFee(idCommand);
            Map<String, Object> resultMap = new HashMap<String, Object>();
            Map<String, Object> dataMap = null;
            List<Map<String, Object>> chargesListMap = new ArrayList<Map<String, Object>>();
            if (result.getFeeList().size() > 0) {
                for (SalesCalculatorFee sf : result.getFeeList()) {

                    dataMap = new HashMap<String, Object>();
                    dataMap.put("chargesName", sf.getSalesChangeItemName());
                    dataMap.put("deductionNode", sf.getFeeNode());// 扣费节点 lihui
                                                                  // update
                    dataMap.put("amount", sf.getResultFee().setScale(2, BigDecimal.ROUND_HALF_UP)); // 保留2位小数
                    dataMap.put("currencySystem", sf.getCurrency());
                    chargesListMap.add(dataMap);
                }
            }
            resultMap.put("chargesList", chargesListMap);
            resultMap.put("total", result.getTotalFee());// 保留2位小数
            responseMsg.setData(resultMap);
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }

    /**
     * 提交国际送仓单
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/submit")
    public String submit(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        SubmitGlobalTransferCommand command = new SubmitGlobalTransferCommand();
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "id");
            ValidateUtil.validMaxLength(json, "id", 20, true);
            command.setId(json.getInteger("id"));
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 组装command
        command.setCtx(CommandContext.getContext());
        globalTransferService.submit(command);
        responseMsg.setData("SUCCESS");

        return SUCCESS;
    }

    /**
     * 查询国际送仓单详情
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/getGlobalTransferDetail")
    public String getGlobalTransferDetail(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        GetGlobalTransferCommand command = new GetGlobalTransferCommand();
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            if (StringUtils.isNotBlank(json.getString("globalTransferNo"))) {
                command.setGlobalTransferNo(json.getString("globalTransferNo"));
            } else {
                ValidateUtil.validNotNull(json, "id");
                ValidateUtil.validMaxLength(json, "id", 20, true);
                command.setId(json.getInteger("id"));
            }
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 组装command
        GlobalTransferOrder order = globalTransferService.getGlobalTransferDetail(command);

        // 组装预约提货时间
        GTOrderCustomerAddress customerAddress = order.getDeliveryAddress();
        if (customerAddress != null) {
            if (customerAddress.getExpectFromDate() != null && customerAddress.getExpectToDate() != null) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
                String pickExpectDate = dateFormat.format(customerAddress.getExpectFromDate());
                String fromTimeStr = timeFormat.format(customerAddress.getExpectFromDate());
                String toTimeStr = timeFormat.format(customerAddress.getExpectToDate());

                order.setPickExpectDate(pickExpectDate);
                order.setTimeFromTo(fromTimeStr + "-" + toTimeStr);
            }
        }
        if ("S".equals(order.getPickServiceCode())) {
            String strDate = DateUtil.parse2String(order.getForecastWarehouseDate(), "yyyy-MM-dd");
            order.setForecastWarehouseDate(DateUtil.parse2Date(strDate, "yyyy-MM-dd"));
        }
        responseMsg.setData(order);

        return SUCCESS;
    }

    /**
     * 编辑国际送仓单
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/editGlobalTransfer")
    public String editGlobalTransfer(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        EditGlobalTransferCommand command = new EditGlobalTransferCommand();
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "id");
            ValidateUtil.validMaxLength(json, "id", 20, true);
            command.setId(json.getInteger("id"));
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        GlobalTransferOrder order = globalTransferService.editGlobalTransfer(command);

        // 组装预约提货时间
        GTOrderCustomerAddress customerAddress = order.getDeliveryAddress();
        if (customerAddress != null) {
            if (customerAddress.getExpectFromDate() != null && customerAddress.getExpectToDate() != null) {
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
                String pickExpectDate = dateFormat.format(customerAddress.getExpectFromDate());
                String fromTimeStr = timeFormat.format(customerAddress.getExpectFromDate());
                String toTimeStr = timeFormat.format(customerAddress.getExpectToDate());

                order.setPickExpectDate(pickExpectDate);
                order.setTimeFromTo(fromTimeStr + "-" + toTimeStr);
            }
        }
        if (!order.getStatus().equals("PD") && !order.getStatus().equals("SB") && !"DR".equals(order.getStatus())) {
            throw new ApiException(ErrorCode.STATUS_NOT_EDIT, "data");
        } else {
            if ("S".equals(order.getPickServiceCode())) {
                String strDate = DateUtil.parse2String(order.getForecastWarehouseDate(), "yyyy-MM-dd");
                order.setForecastWarehouseDate(DateUtil.parse2Date(strDate, "yyyy-MM-dd"));
            }
            responseMsg.setData(order);
        }

        return SUCCESS;
    }

    /**
     * 作废国际送仓单
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/disable")
    public String disable(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        DisableGlobalTransferCommand command = new DisableGlobalTransferCommand();
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validMaxLength(json, "id", 20, true);
            ValidateUtil.validNotNull(json, "orderNo");
            ValidateUtil.validNotNull(json, "type");
            command.setId(json.getInteger("id"));
            command.setOrderNo(json.getString("orderNo"));
            command.setSource(ApiConstant.SET_SOURCE);
            command.setType(json.getString("type"));
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 组装command
        globalTransferService.disable(command);
        responseMsg.setData("SUCCESS");

        return SUCCESS;
    }

    /**
     * 根据包裹ID查询产品信息
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/getProductByPackageId")
    public String getProductByPackageId(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        GetCustomerPackageLineByPackageIdCommand command = new GetCustomerPackageLineByPackageIdCommand();
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "packageId");
            ValidateUtil.validMaxLength(json, "packageId", 20, true);
            command.setPackageId(json.getInteger("packageId"));
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        List<CustomerPackageLine> packageLineList = customerPackageService.queryCustomerPackageLineList(command);
        responseMsg.setData(packageLineList);

        return SUCCESS;
    }

    private Searchable buildSearchPageParams(JSONObject json) {
        int pageNo = ApiConstant.PAGE_NO_DEFAULT;
        int pageSize = ApiConstant.PAGE_SIZE_DEFAULT;
        // pageParams
        if (json != null && json.containsKey("pageParams")) {
            JSONObject pageParams = json.getJSONObject("pageParams");
            // pageNo
            if (pageParams.containsKey("pageNo")) {
                pageNo = pageParams.getInteger("pageNo");
            }
            // pageSize
            if (pageParams.containsKey("pageSize")) {
                pageSize = pageParams.getInteger("pageSize");
            }
        }
        Searchable search = Searchable.newSearchable();
        search.setPage(pageNo, pageSize);
        search.addSort(new Sort(Direction.DESC, "CREATED"));
        return search;
    }

    private void validpageParams(JSONObject json) {
        // pageParams
        if (json.containsKey("pageParams")) {
            Object obj = json.get("pageParams");
            if (obj instanceof JSONObject) {
                JSONObject pageParams = (JSONObject) obj;
                // pageNo
                ValidateUtil.validInteger(pageParams, "pageNo");
                // pageSize
                ValidateUtil.validInteger(pageParams, "pageSize");
                if (pageParams.containsKey("pageNo")) {
                    int pageNo = pageParams.getInteger("pageNo");
                    if (pageNo < 1) {
                        throw new ApiException(ErrorCode.FIELD_ERROR, "pageNo");
                    }
                }
                if (pageParams.containsKey("pageSize")) {
                    int pageSize = pageParams.getInteger("pageSize");
                    if (pageSize < 1) {
                        throw new ApiException(ErrorCode.FIELD_ERROR, "pageSize");
                    }
                }
            } else {
                throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "pageParams");
            }
        }
    }

    /**
     * 校验单据信息是否必填、长度、类型
     * 
     * @param json
     */
    private void validateGlobalTransfer(JSONObject json) {
        // 必填字段不允许修改为空
        boolean required = true;
        // sellerOrderNo
        // ValidateUtil.validNotNull(json, "sellerOrderNo");
        ValidateUtil.validMaxLength(json, "sellerOrderNo", 60);
        // winitProductCode
        ValidateUtil.validNotNull(json, "winitProductCode");
        ValidateUtil.validMaxLength(json, "winitProductCode", 50, required);
        // winitProductName
        ValidateUtil.validMaxLength(json, "winitProductName", 60, required);
        // winitProductName
        ValidateUtil.validNotNull(json, "winitProductType");
        ValidateUtil.validMaxLength(json, "winitProductType", 32, required);

        // lihui FBA add
        // shippmentId
        ValidateUtil.validNotNull(json, "shippmentId");
        ValidateUtil.validMaxLength(json, "shippmentId", 32, required);
        // winitProductCode
        ValidateUtil.validNotNull(json, "countryCode");
        ValidateUtil.validMaxLength(json, "countryCode", 32, required);
        // countryName
        ValidateUtil.validMaxLength(json, "countryName", 60, required);
        // logisticsPlanId
        ValidateUtil.validNotNull(json, "logisticsPlanId");
        ValidateUtil.validMaxLength(json, "logisticsPlanId", 20, required);
        // logisticsPlanName
        ValidateUtil.validNotNull(json, "logisticsPlanName");
        ValidateUtil.validMaxLength(json, "logisticsPlanName", 32, required);
        // FBA end

        // pickServiceCode
        ValidateUtil.validNotNull(json, "pickServiceCode");
        ValidateUtil.validMaxLength(json, "pickServiceCode", 20, required);
        // pickServiceName
        ValidateUtil.validNotNull(json, "pickServiceName");
        ValidateUtil.validMaxLength(json, "pickServiceName", 60, required);
        // warehouseCode
        ValidateUtil.validNotNull(json, "warehouseCode");
        ValidateUtil.validMaxLength(json, "warehouseCode", 30, required);
        // warehouseName
        ValidateUtil.validNotNull(json, "warehouseName");
        ValidateUtil.validMaxLength(json, "warehouseName", 60, required);
        if (json.getString("pickServiceCode").equals("P")) {// winit提货
            // deliveryAddressCode
            ValidateUtil.validNotNull(json, "deliveryAddressCode");
            ValidateUtil.validMaxLength(json, "deliveryAddressCode", 64, required);
        }
        if (json.getString("pickServiceCode").equals("S")) {// 自发物流
            // forecastWarehouseDate
            ValidateUtil.validNotNull(json, "forecastWarehouseDate");
            // expressNo
            ValidateUtil.validNotNull(json, "expressNo");
            ValidateUtil.validMaxLength(json, "expressNo", 60, required);
        }
        // destinationAddressCode
        ValidateUtil.validNotNull(json, "destinationAddressCode");
        ValidateUtil.validMaxLength(json, "destinationAddressCode", 64, required);

        // 进口报关规则
        ValidateUtil.validNotNull(json, "importDeclarationRuleCode");
        ValidateUtil.validMaxLength(json, "importDeclarationRuleCode", 60, true);

        // 出口报关类型
        ValidateUtil.validNotNull(json, "customsDeclarationType");
        ValidateUtil.validMaxLength(json, "customsDeclarationType", 60, true);

        if ("CEOR".equals(json.getString("customsDeclarationType"))) {
            // exporterId
            ValidateUtil.validNotNull(json, "exporterId");
            ValidateUtil.validMaxLength(json, "exporterId", 20, true);
            // exporterName
            ValidateUtil.validNotNull(json, "exporterName");
            ValidateUtil.validMaxLength(json, "exporterName", 60, true);
        }
    }

    /**
     * 校验单据信息是否必填、长度、类型
     * 
     * @param json
     */
    private void validatePackage(JSONObject json, String winitProductType) {
        // 必填字段不允许修改为空
        boolean required = true;
        // customerPackageBarcode
        ValidateUtil.validNotNull(json, "customerPackageBarcode");
        ValidateUtil.validMaxLength(json, "customerPackageBarcode", 60, required);
        // customerPackageBarcode是否存在特殊字符
        if (!json.getString("customerPackageBarcode").matches("[^@#$%&(){}<>]{0,}")) {
            throw new ApiException(ErrorCode.NOT_INPUT_SPECHARS, "customerPackageBarcode");
        }
        // declaredCode
        String declaredCode = json.getString("declaredCode");
        if (StringUtils.isEmpty(declaredCode)) {
            ValidateUtil.validNotNull(json, "FNSKU");
        }
        ValidateUtil.validMaxLength(json, "declaredCode", 500, required);// 和ERP属性长度保持一致

        // quantity
        ValidateUtil.validNotNull(json, "quantity");
        ValidateUtil.validMaxLength(json, "quantity", 20, required);

        // 校验quantity是否为数字
        if (!ValidateUtil.isIntNumber(json.getString("quantity"))) {
            throw new ApiException(ErrorCode.IMPORT_PRODUCT_QUANTITY_ERROR, "quantity");
        }

        if (Integer.parseInt(json.getString("quantity")) <= 0) {
            throw new ApiException(ErrorCode.COMPLETE_TO_ZERO, "quantity");
        }

        // 重量
        ValidateUtil.validNotNull(json, "importWeight");
        PrecisionValidateUtils.validateIsNumber(json.getString("importWeight"), "importWeight");
        PrecisionValidateUtils.precisionValidateMaxDigit(json.getBigDecimal("importWeight").setScale(6,
            BigDecimal.ROUND_HALF_UP),
            "importWeight",
            16);
        // 长
        ValidateUtil.validNotNull(json, "importLength");
        PrecisionValidateUtils.validateIsNumber(json.getString("importLength"), "importLength");
        PrecisionValidateUtils.precisionValidateMaxDigit(json.getBigDecimal("importLength").setScale(2,
            BigDecimal.ROUND_HALF_UP),
            "importLength",
            16);
        // 宽
        ValidateUtil.validNotNull(json, "importWidth");
        PrecisionValidateUtils.validateIsNumber(json.getString("importWidth"), "importWidth");
        PrecisionValidateUtils.precisionValidateMaxDigit(json.getBigDecimal("importWidth").setScale(2,
            BigDecimal.ROUND_HALF_UP),
            "importWidth",
            16);
        // 高
        ValidateUtil.validNotNull(json, "importHeight");
        PrecisionValidateUtils.validateIsNumber(json.getString("importHeight"), "importHeight");
        PrecisionValidateUtils.precisionValidateMaxDigit(json.getBigDecimal("importHeight").setScale(2,
            BigDecimal.ROUND_HALF_UP),
            "importHeight",
            16);
    }

    /**
     * 封装校验订单对象
     * 
     * @param json
     * @return
     */
    private SaveGlobalTransferCommand buildOrderValidateCommand(JSONObject json) {
        SaveGlobalTransferCommand command = new SaveGlobalTransferCommand();
        GlobalTransferOrder order = new GlobalTransferOrder();
        GTOrderCustomerAddress customerAddress = new GTOrderCustomerAddress();
        if (json.containsKey("id")) {
            order.setId(json.getInteger("id"));
        }
        if (json.containsKey("globalTransferNo")) {
            order.setSellerOrderNo(json.getString("globalTransferNo"));
        }
        if (json.containsKey("sellerOrderNo")) {
            order.setSellerOrderNo(json.getString("sellerOrderNo"));
        }
        if (json.containsKey("winitProductCode")) {
            order.setWinitProductCode(json.getString("winitProductCode"));
        }
        if (json.containsKey("winitProductName")) {
            order.setWinitProductName(json.getString("winitProductName"));
        }
        if (json.containsKey("winitProductType")) {
            order.setWinitProductType(json.getString("winitProductType"));
        }
        // lihui FBA add
        if (json.containsKey("shippmentId")) {
            order.setShippmentId(json.getString("shippmentId"));
        }
        if (json.containsKey("countryCode")) {
            order.setCountryCode(json.getString("countryCode"));
        }
        if (json.containsKey("countryName")) {
            order.setCountryName(json.getString("countryName"));
        }
        if (json.containsKey("logisticsPlanId")) {
            order.setLogisticsPlanId(json.getLong("logisticsPlanId"));
        }
        if (json.containsKey("logisticsPlanName")) {
            order.setLogisticsPlanName(json.getString("logisticsPlanName"));
        }
        // FBA end
        if (json.containsKey("pickServiceCode")) {
            order.setPickServiceCode(json.getString("pickServiceCode"));
        }
        if (json.containsKey("pickServiceName")) {
            order.setPickServiceName(json.getString("pickServiceName"));
        }
        if (json.containsKey("warehouseCode")) {
            order.setWarehouseCode(json.getString("warehouseCode"));
        }
        if (json.containsKey("warehouseName")) {
            order.setWarehouseName(json.getString("warehouseName"));
        }
        if (json.containsKey("deliveryAddressCode")) {
            order.setDeliveryAddressCode(json.getString("deliveryAddressCode"));
        }
        if (json.containsKey("forecastWarehouseDate")) {
            order.setForecastWarehouseDate(json.getDate("forecastWarehouseDate"));
        }
        if (json.containsKey("expressNo")) {
            order.setExpressNo(json.getString("expressNo"));
        }
        if (json.containsKey("destinationAddressCode")) {
            order.setDestinationAddressCode(json.getString("destinationAddressCode"));
        }
        if (json.containsKey("transportModeCode")) {
            order.setTransportModeCode(json.getString("transportModeCode"));
        }
        if (json.containsKey("transportModeName")) {
            order.setTransportModeName(json.getString("transportModeName"));
        }
        if (json.containsKey("flightVoyageId")) {
            order.setFlightVoyageId(json.getInteger("flightVoyageId"));
        }
        if (json.containsKey("seaVoyageId")) {
            order.setSeaVoyageId(json.getInteger("seaVoyageId"));
        }
        if (json.containsKey("flightVoyageName")) {
            order.setFlightVoyageName(json.getString("flightVoyageName"));
        }

        if (json.containsKey("importerId")) {
            order.setImporterId(json.getInteger("importerId"));
        }
        if (json.containsKey("importerName")) {
            order.setImporterName(json.getString("importerName"));
        }
        if (json.containsKey("exporterId")) {
            order.setExporterId(json.getInteger("exporterId"));
        }
        if (json.containsKey("exporterCode")) {
            order.setExporterCode(json.getString("exporterCode"));
        }
        if (json.containsKey("exporterName")) {
            order.setExporterName(json.getString("exporterName"));
        }
        // 进口报关规则编码
        if (json.containsKey("importDeclarationRuleCode")) {
            order.setImportDeclarationRuleCode(json.getString("importDeclarationRuleCode"));
        }
        // EOR类型
        if (json.containsKey("customsDeclarationType")) {
            order.setCustomsDeclarationType(json.getString("customsDeclarationType"));
        }
        JSONArray array = json.getJSONArray("packageList");
        if (array != null) {
            List<CustomerPackage> packageList = new ArrayList<CustomerPackage>();
            for (Object obj : array) {
                JSONObject pacakge = (JSONObject) obj;
                CustomerPackage customerPackage = new CustomerPackage();
                customerPackage.setCustomerPackageBarcode(pacakge.getString("winitPackageBarcode"));
                JSONArray lineArray = pacakge.getJSONArray("packageLineList");
                List<CustomerPackageLine> packageLineList = new ArrayList<CustomerPackageLine>();
                for (Object object : lineArray) {
                    JSONObject pacakgeLine = (JSONObject) object;
                    CustomerPackageLine customerPackageLine = new CustomerPackageLine();
                    customerPackageLine.setDeclaredCode(pacakgeLine.getString("declaredCode"));
                    customerPackageLine.setDeclaredNameCn(pacakgeLine.getString("declaredNameCn"));
                    customerPackageLine.setDeclaredNameEn(pacakgeLine.getString("declaredNameEn"));
                    customerPackageLine.setSpecification(pacakgeLine.getString("specification"));
                    customerPackageLine.setQuantity(pacakgeLine.getInteger("quantity"));
                    packageLineList.add(customerPackageLine);
                }
                customerPackage.setCustomerPackageLineList(packageLineList);
                packageList.add(customerPackage);
            }
        }

        if (json.containsKey("date") && ValidateUtil.isNotNull(json, "date")) {
            String[] dates = json.get("date").toString().split("\\|");
            customerAddress.setExpectFromDate(DateUtil.parse2Date(dates[0], DateUtil.FULL_DATE_STRING));
            customerAddress.setExpectToDate(DateUtil.parse2Date(dates[1], DateUtil.FULL_DATE_STRING));
        } else if (json.containsKey("formatDate") && ValidateUtil.isNotNull(json, "formatDate")) {
            String[] dates = json.get("formatDate").toString().split("\\|");
            customerAddress.setExpectFromDate(DateUtil.parse2Date(dates[0], DateUtil.FULL_DATE_STRING));
            customerAddress.setExpectToDate(DateUtil.parse2Date(dates[1], DateUtil.FULL_DATE_STRING));
        } else if (json.containsKey("dateExpectFrom") && json.containsKey("dateExpectTo")) {
            customerAddress.setExpectFromDate(DateUtil.parse2Date(json.getString("dateExpectFrom"),
                DateUtil.FULL_DATE_STRING));
            customerAddress.setExpectToDate(DateUtil.parse2Date(json.getString("dateExpectTo"),
                DateUtil.FULL_DATE_STRING));
        }
        order.setDeliveryAddress(customerAddress);
        command.setGlobalTransferOrder(order);
        return command;
    }

    // 效验重量价格大于0
    public void positiveNumber(JSONObject json, String key) {
        if (isExistValue(json, key) && ValidateUtil.isBigDecimal(json.getString(key))) {
            BigDecimal bd = new BigDecimal(json.getString(key));
            if (bd.compareTo(new BigDecimal("0")) <= 0) {
                throw new ApiException(ErrorCode.FIELD_INPUT_ERROR, key);
            }
        }
    }

    // 效验大于0,批量导入提示
    public void positiveNumberImport(JSONObject json, String key, String xmlKye) {
        if (isExistValue(json, key) && ValidateUtil.isBigDecimal(json.getString(key))) {
            BigDecimal bd = new BigDecimal(json.getString(key));
            if (bd.compareTo(new BigDecimal("0")) <= 0) {
                throw new ApiException(ErrorCode.FIELD_INPUT_ERROR, xmlKye);
            }
        }

    }

    // 判断非必填字段是否有值
    public boolean isExistValue(JSONObject jsonObject, String key) {
        if (jsonObject.containsKey(key)) {
            return !"".equals(jsonObject.getString(key).trim());
        }
        return false;
    }

    private PageGlobalTransferCommand buildPageGlobalTransferCommand(JSONObject json) {
        PageGlobalTransferCommand command = new PageGlobalTransferCommand();
        if (json.containsKey("globalTransferNo")) {
            command.setGlobalTransferNo(json.getString("globalTransferNo"));
        }
        if (json.containsKey("sellerOrderNo")) {
            command.setSellerOrderNo(json.getString("sellerOrderNo"));
        }
        if (json.containsKey("winitProductCode")) {
            command.setProductCode(json.getString("winitProductCode"));
        }
        if (json.containsKey("warehouseCode")) {
            command.setWarehouseCode(json.getString("warehouseCode"));
        }
        if (json.containsKey("transportModeCode")) {
            command.setTransportModeCode(json.getString("transportModeCode"));
        }
        if (json.containsKey("status")) {
            command.setStatus(json.getString("status"));
        }
        if (json.containsKey("startDate")) {
            ValidateUtil.validDateString(json, "startDate", DateUtil.SIMPLE_DATE_STRING);
            command.setStartDate(json.getDate("startDate"));
        }
        if (json.containsKey("endDate")) {
            ValidateUtil.validDateString(json, "endDate", DateUtil.SIMPLE_DATE_STRING);
            command.setEndDate(json.getDate("endDate"));
        }
        if (json.containsKey("pscCode")) {
            command.setPscCode(json.getString("pscCode"));
        }

        return command;
    }

    /**
     * 根据产品查询国家列表
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/getCountryListByProductCode")
    public String getCountryListByProductCode(@ModelAttribute RequestMsg requestMsg,
                                              @ModelAttribute ResponseMsg responseMsg) {
        String productCode = null;
        String productType = null;
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "productCode");
            productCode = json.getString("productCode");
            productType = json.getString("winitProductType");
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        if (StringUtils.isNotEmpty(productType) && !"GTP".equals(productType)) {
            QueryDestCountryCommand queryCommand = new QueryDestCountryCommand();
            queryCommand.setProductCode(productCode);
            queryCommand.setDestDistType(PmsEnumType.EnumDistrictType.BUYER.getType());
            Bpartner bpartner = CommandContext.getContext().get(ApiConstant.API_BPARTNER);
            if (bpartner != null) {
                queryCommand.setCustomerCode(bpartner.getValue());
            } else {
                queryCommand.setCustomerCode(CommandContext.getContext().getUserId());
            }
            responseMsg.setData(productLogisticsDistService.queryDestCountryMapByProductCode(queryCommand));
        } else {
            QueryWarehouseLogisticsDistCommand command = new QueryWarehouseLogisticsDistCommand();
            command.setProductCode(productCode);
            command.setDistType(PmsEnumType.EnumDistrictType.BUYER.getType());
            List<LogisticsDist> distList = logisticsdistService.queryWarehouseList(command);
            if (null != distList && distList.size() > 0) {
                Map<String, String> map = new HashMap<String, String>();
                CountryCodeCommand codeCommand = new CountryCodeCommand();
                for (LogisticsDist logisticsDist : distList) {
                    codeCommand.setCountryCode(logisticsDist.getCountryCode());
                    Country country = countryService.getCountryByCode(codeCommand);
                    if (null != country) {
                        map.put(logisticsDist.getCountryCode(),
                            StringUtils.isEmpty(country.getCountryName()) ? (StringUtils.isEmpty(country.getCountryName2()) ? country.getRemark() : country.getCountryName2()) : country.getCountryName());
                    } else {
                        throw new ApiException("国际编码：{}，对应的国家不存在", logisticsDist.getCountryCode());
                    }
                }
                responseMsg.setData(map);
            }
        }
        return SUCCESS;
    }

    @RequestMapping(value = "/getVoidOrderRecord")
    public String getVoidOrderRecord(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        VoidInboundOrderCommand command = new VoidInboundOrderCommand();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "orderNo");
            command.setOrderNo(json.getString("orderNo"));
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 调用接口查询作废订单详情
        InboundVoidOrderRecordVo vo = inboundOrderService.getVoidOrderRecord(command);
        responseMsg.setData(vo);
        responseMsg.setMsg("success");
        return SUCCESS;
    }

    @RequestMapping(value = "/queryTransferWarehouseList")
    public String queryTransferWarehouseList(@ModelAttribute RequestMsg requestMsg,
                                             @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        QueryReceiveWarehouseListCommand command = new QueryReceiveWarehouseListCommand();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            // winitProductCode
            ValidateUtil.validNotNull(json, "winitProductCode");
            ValidateUtil.validMaxLength(json, "winitProductCode", 50, true);
            // countryCode
            ValidateUtil.validNotNull(json, "countryCode");
            ValidateUtil.validMaxLength(json, "countryCode", 32, true);

            command.setProductCode(json.getString("winitProductCode"));
            command.setSlaDestDistCountryCode(json.getString("countryCode"));
            command.setSlaStartDistType(PmsEnumType.EnumDistrictType.TRANSFERWAREHOUSE.getType());
            command.setSlaDate(new Date());
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        Map<String, String> map = productLogisticsDistService.querySlaStartDistWarehouseList(command);
        responseMsg.setData(map);
        responseMsg.setMsg("success");
        return SUCCESS;
    }

    @RequestMapping(value = "/queryDestWarehouseList")
    public String queryDestWarehouseList(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        Object obj = requestMsg.getData();
        QueryDestWarehouseListCommand command = new QueryDestWarehouseListCommand();
        String winitProductCode = "";
        String winitProductType = "";
        String countryCode = "";
        String inspWarehouseCode = "";
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            // winitProductCode
            ValidateUtil.validNotNull(json, "winitProductCode");
            ValidateUtil.validMaxLength(json, "winitProductCode", 32, true);
            winitProductCode = json.getString("winitProductCode");
            // winitProductType
            ValidateUtil.validNotNull(json, "winitProductType");
            ValidateUtil.validMaxLength(json, "winitProductType", 32, true);
            winitProductType = json.getString("winitProductType");
            // countryCode
            ValidateUtil.validNotNull(json, "countryCode");
            ValidateUtil.validMaxLength(json, "countryCode", 32, true);
            countryCode = json.getString("countryCode");
            // inspWarehouseCode
            ValidateUtil.validNotNull(json, "inspWarehouseCode");
            ValidateUtil.validMaxLength(json, "inspWarehouseCode", 32, true);
            inspWarehouseCode = json.getString("inspWarehouseCode");

            command.setProductCode(json.getString("winitProductCode"));
            command.setSlaDestDistCountryCode(json.getString("countryCode"));
            command.setInspWarehouseCode(json.getString("inspWarehouseCode"));
            command.setSlaDestDistType(PmsEnumType.EnumDistrictType.PORTWAREHOUSE.getType());
            command.setSlaDate(new Date());
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        if (!"GTP".equalsIgnoreCase(winitProductType)) {
            responseMsg.setData(productLogisticsDistService.querySlaEndDistWarehouseList(command));
        } else {
            responseMsg.setData(this.queryDestWarehouseList(winitProductCode, inspWarehouseCode, countryCode));
        }
        responseMsg.setMsg("success");
        return SUCCESS;
    }

    @RequestMapping(value = "/saveFirstStep")
    public String saveFirstStep(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        SaveGlobalTransferCommand command = null;
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            // 校验单据信息是否必填、长度、类型
            // sellerOrderNo
            ValidateUtil.validMaxLength(json, "sellerOrderNo", 60);
            // winitProductCode
            ValidateUtil.validNotNull(json, "winitProductCode");
            ValidateUtil.validMaxLength(json, "winitProductCode", 50, true);
            // winitProductName
            ValidateUtil.validMaxLength(json, "winitProductName", 60, true);
            // winitProductType
            ValidateUtil.validNotNull(json, "winitProductType");
            ValidateUtil.validMaxLength(json, "winitProductType", 32, true);
            // shippmentId
            if (!PmsConstants.PRODUCT_CATEGORY_GTP22.equals(json.getString("winitProductType"))
                && !PmsConstants.PRODUCT_CATEGORY_GTP32.equals(json.getString("winitProductType"))) {
                ValidateUtil.validNotNull(json, "shippmentId");
                ValidateUtil.validMaxLength(json, "shippmentId", 32, true);
            }
            // countryCode
            ValidateUtil.validNotNull(json, "countryCode");
            ValidateUtil.validMaxLength(json, "countryCode", 32, true);
            // countryName
            ValidateUtil.validMaxLength(json, "countryName", 60, true);
            // 组装command
            command = (SaveGlobalTransferCommand) buildOrderValidateCommand(json);
            command.setCtx(CommandContext.getContext());
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 保存单据基本信息
        Integer id = globalTransferService.saveFirstStep(command);
        responseMsg.setData(id);

        return SUCCESS;
    }

    @RequestMapping(value = "/saveThirdStep")
    public String saveThirdStep(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        SaveGlobalTransferCommand command = null;
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;

            // 1.校验国际送仓单号
            ValidateUtil.validNotNull(json, "id");
            ValidateUtil.validMaxLength(json, "id", 20, true);

            // 2.校验提货服务:P:Winit提货，S:自发物流
            ValidateUtil.validNotNull(json, "pickServiceCode");
            ValidateUtil.validMaxLength(json, "pickServiceCode", 20, true);
            // TODO 这里不应该校验提货服务名称
            ValidateUtil.validNotNull(json, "pickServiceName");
            ValidateUtil.validMaxLength(json, "pickServiceName", 60, true);

            // 3.选择提货服务后的校验
            if (json.getString("pickServiceCode").equals("P")) {
                // Winit揽收的，必填提货地址编码
                ValidateUtil.validNotNull(json, "deliveryAddressCode");
                ValidateUtil.validMaxLength(json, "deliveryAddressCode", 64, true);
            } else if (json.getString("pickServiceCode").equals("S")) {// 自发物流
                // forecastWarehouseDate
                ValidateUtil.validNotNull(json, "forecastWarehouseDate"); // 预计到仓时间必填
                ValidateUtil.validNotNull(json, "expressNo"); // 快递单号必填
                ValidateUtil.validMaxLength(json, "expressNo", 60, true);
            } else {
                throw new ApiException(ErrorCode.FIELD_VALUE_ERROR, "pickServiceCode");
            }

            // 4. 验货仓（中转仓）验证
            ValidateUtil.validNotNull(json, "warehouseCode");
            ValidateUtil.validMaxLength(json, "warehouseCode", 30, true);
            // TODO 这里不需要验证 warehouseName
            ValidateUtil.validNotNull(json, "warehouseName");
            ValidateUtil.validMaxLength(json, "warehouseName", 60, true);

            // 组装command
            command = GlobalTransferOrderBuilder.buildThirdOrderCommand(json);
            command.setCtx(CommandContext.getContext());
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 保存单据基本信息
        Integer id = globalTransferService.saveThirdStep(command);
        responseMsg.setData(id);

        return SUCCESS;
    }

    @RequestMapping(value = "/saveFourStep")
    public String saveFourStep(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg) {
        SaveGlobalTransferCommand command = null;
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            // 校验单据信息是否必填、长度、类型
            // id
            ValidateUtil.validNotNull(json, "id");
            ValidateUtil.validMaxLength(json, "id", 20, true);
            // winitProductType
            ValidateUtil.validNotNull(json, "winitProductType");
            ValidateUtil.validMaxLength(json, "winitProductType", 32, true);
            // destinationAddressCode
            ValidateUtil.validNotNull(json, "destinationAddressCode");
            ValidateUtil.validMaxLength(json, "destinationAddressCode", 64, true);

            // 进口报关规则
            ValidateUtil.validNotNull(json, "importDeclarationRuleCode");
            ValidateUtil.validMaxLength(json, "importDeclarationRuleCode", 60, true);

            // importerId
            // ValidateUtil.validNotNull(json, "importerId");
            ValidateUtil.validMaxLength(json, "importerId", 20, false);
            // importerName
            // ValidateUtil.validNotNull(json, "importerName");
            ValidateUtil.validMaxLength(json, "importerName", 60, false);

            // 出口报关类型
            ValidateUtil.validNotNull(json, "customsDeclarationType");
            ValidateUtil.validMaxLength(json, "customsDeclarationType", 60, true);

            if ("CEOR".equals(json.getString("customsDeclarationType"))) {
                // exporterId
                ValidateUtil.validNotNull(json, "exporterId");
                ValidateUtil.validMaxLength(json, "exporterId", 20, true);
                // exporterName
                ValidateUtil.validNotNull(json, "exporterName");
                ValidateUtil.validMaxLength(json, "exporterName", 60, true);
            }
            // 组装command
            command = (SaveGlobalTransferCommand) buildOrderValidateCommand(json);
            command.setCtx(CommandContext.getContext());
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        // 保存单据基本信息
        Integer id = globalTransferService.saveFourStep(command);
        responseMsg.setData(id);

        return SUCCESS;
    }

    private Map<String, String> queryDestWarehouseList(String productCode, String inspWarehouseCode, String countryCode) {

        logger.info("queryDestWarehouseList 入参:[{}],[{}],[{}]", new Object[] { productCode, inspWarehouseCode,
                countryCode });
        // 根据验货仓查询目的仓列表
        WinitProductQueryCommand productCommand = new WinitProductQueryCommand();
        productCommand.setCode(productCode);
        WinitProduct product = winitProductService.queryProduct(productCommand);
        if (null == product) {
            logger.error("queryDestWarehouseList 产品[{}]不存在", productCode);
            return null;
        }
        LogisticsDist beginDist = null;
        Map<String, String> distMap = new HashMap<String, String>();
        LogisticsQueryCommand command = new LogisticsQueryCommand();
        command.setWinitProductId(product.getWinitProductId());
        List<LogisticsDist> distList = logisticsdistService.queryWinitLogisticsDistByPorductId(command);
        if (null != distList && distList.size() > 0) {
            for (LogisticsDist dist : distList) {
                if ("Warehouse".equals(dist.getDistrictType()) && inspWarehouseCode.equals(dist.getCode())) {
                    beginDist = dist;
                }
                if ("DestWarehouse".equals(dist.getDistrictType())
                    && countryCode.equalsIgnoreCase(dist.getCountryCode())) {
                    distMap.put(dist.getCode(), dist.getName());
                }
            }
        }
        if (beginDist == null) {
            logger.error("queryDestWarehouseList 产品[{}]分区[{}]不存在", productCode, inspWarehouseCode);
            return null;
        }
        WinitSlaQueryCommand slaCommand = new WinitSlaQueryCommand();
        slaCommand.setWinitProductId(product.getWinitProductId());
        List<WinitSla> slaList = winitSlaService.queryWinitSlaByPorductId(slaCommand);
        if (slaList == null || slaList.size() == 0) {
            logger.error("queryDestWarehouseList 产品[{}]SLA不存在", productCode);
            return null;
        }
        Map<String, String> map = new HashMap<String, String>();
        Date date = new Date();
        for (WinitSla sla : slaList) {
            if (sla.getEffective().getTime() > date.getTime() || sla.getExpiry().getTime() < date.getTime()
                || beginDist.getWinitLogisticsdistId().longValue() != sla.getSlaBegian().longValue()) {
                continue;
            }
            if (distMap.get(sla.getSlaEndCode()) != null) {
                map.put(sla.getSlaEndCode(), sla.getSlaEndName());
            }
        }
        logger.info("queryDestWarehouseList 产品[{}]目的仓列表[{}]", new Object[] { productCode, JSON.toJSONString(map) });
        return map;
    }

    /**
     * 分页查询包裹列表
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     * @throws ParseException
     */
    @RequestMapping(value = "/pageValidPackageList")
    public String pageValidPackageList(@ModelAttribute RequestMsg requestMsg, @ModelAttribute ResponseMsg responseMsg)
                                                                                                                      throws ParseException {
        Object obj = requestMsg.getData();
        GetByGlobalTransferOrderByNoCommand command = new GetByGlobalTransferOrderByNoCommand();
        CommandContext ctx = CommandContext.getContext();
        command.setCtx(ctx);
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            validpageParams(json);
            ValidateUtil.validNotNull(json, "globalTransferOrderNo");
            command.setGlobalTransferOrderNo(json.getString("globalTransferOrderNo"));
            if (json.containsKey("customerPackageBarcode")) {
                command.setCustomerPackageBarcode(json.getString("customerPackageBarcode"));
            }
            if (json.containsKey("isAscan")) {
                command.setIsAscan(json.getString("isAscan"));
            }
            if (json.containsKey("isDscan")) {
                command.setIsDscan(json.getString("isDscan"));
            }
            Page<CustomerPackageVO> page = customerPackageService.pageValidPackageList(command);
            if (page != null) {
                Map<String, Object> pageMap = new HashMap<String, Object>();
                pageMap.put("pageNo", page.getPageable().getPageNumber());
                pageMap.put("pageSize", page.getPageable().getPageSize());
                pageMap.put("totalCount", page.getTotalElements());

                Map<String, Object> data = new HashMap<String, Object>();
                data.put("list", page.getContent());
                data.put("pageParams", pageMap);
                responseMsg.setData(data);
            }

        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        return SUCCESS;
    }

    /**
     * 根据订单号查询有效包裹列表
     * 
     * @param requestMsg
     * @param responseMsg
     * @return
     */
    @RequestMapping(value = "/queryValidCustomerPackageList")
    public String queryValidCustomerPackageList(@ModelAttribute RequestMsg requestMsg,
                                                @ModelAttribute ResponseMsg responseMsg) {
        GetByGlobalTransferOrderByNoCommand command = new GetByGlobalTransferOrderByNoCommand();
        Object obj = requestMsg.getData();
        if (obj instanceof JSONObject) {
            JSONObject json = (JSONObject) obj;
            ValidateUtil.validNotNull(json, "globalTransferOrderNo");
            command.setGlobalTransferOrderNo(json.getString("globalTransferOrderNo"));
        } else {
            throw new ApiException(ErrorCode.FIELD_TYPE_ERROR, "data");
        }
        command.setIsAbnormal("N");
        command.setIsCoverDeduction("N");
        List<CustomerPackage> packageList = customerPackageService.queryValidCustomerPackageList(command);
        responseMsg.setData(packageList);

        return SUCCESS;
    }
}
